/*                      简易画板
功能包括：
1.画画 2.选色 3.修改画笔大小 4.清屏 5.撤销与恢复 6.形状选择 7.画布选择 8.保存图片
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/mman.h>
#include <linux/input.h>

#include "show_bmp.h"
#include "save_bmp.h"
#include "drawing_board.h"

int undo_top = -1;                                                 // 撤销栈顶指针
int redo_top = -1;                                                 // 恢复栈顶指针
int color[COLOR_COUNT] = {BLACK, RED, GREEN, BLUE, YELLOW, WHITE}; // 颜色数组
int color_index = 0;                                               // 颜色选择
int x = -1, y = -1;                                                // 坐标初始值是-1
static int last_x = -1, last_y = -1;                               // 上一个触摸点坐标
int line = 10;                                                     // 绘制线条宽度
int draw_mode = 0;                                                 // 画笔模式选择

int drawing_board(char *account)
{

    // 打开屏幕设备文件并内存映射
    int lcd_fd = open("/dev/fb0", O_RDWR);
    int(*lcd_mmap)[SCREEN_WIDTH] = (int(*)[SCREEN_WIDTH])mmap(NULL, SCREEN_WIDTH * SCREEN_HEIGHT * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
    LCD_clear(0);

    // 打开触摸屏设备文件
    int touch_fd = open("/dev/input/event0", O_RDWR);
    if (touch_fd < 0)
    {
        perror("打开触摸设备失败");
        return -1;
    }
    printf("当前用户: %s\n", account);

    state_init();
    struct input_event touch_event;

    while (1)
    {

        // 读取触摸屏设备文件数据
        int read_ret = read(touch_fd, &touch_event, sizeof(struct input_event));
        if (read_ret < 0)
        {
            perror("读取触摸事件失败");
            return -1;
        }
        // 事件处理
        handle_touch_event(touch_event, lcd_mmap, account);

        if (touch_event.type == EV_KEY)
        {
            if (touch_event.code == BTN_TOUCH && touch_event.value == 1)
            {
                // 左上角功能区
                if (x > 40 & x < 80 & y <= 40) // 画布区域填充当前颜色
                {
                    LCD_clear(1);
                }
                else if (x > 80 & x < 120 & y <= 40) // 画笔模式选择
                {
                    draw_mode = 0;
                }
                else if (x > 120 & x < 160 & y <= 40)
                {
                    draw_mode = 1;
                }
                else if (x > 160 & x < 200 & y <= 40)
                {
                    draw_mode = 2;
                }

                if (y <= 40 && x <= 40) // 退出程序
                    goto exit;
            }
        }
    }
exit:
    close(touch_fd);
    munmap(lcd_mmap, SCREEN_WIDTH * SCREEN_HEIGHT * 4);
    close(lcd_fd);
    return 0;
}

// 初始化撤销栈
void state_init()
{
    for (int i = 0; i < STACK_SIZE; ++i)
    {
        memset(undo_stack[i].data, 0, sizeof(int) * SCREEN_WIDTH * SCREEN_HEIGHT);
    }
    undo_top = -1; // 重置栈顶指针
}

// 将当前的显示缓冲区状态压入撤销栈
void save_state(int (*lcd_mmap)[SCREEN_WIDTH])
{
    if (undo_top < STACK_SIZE - 1) // 确保不超过栈的最大深度
    {
        undo_top++;
        // 保存屏幕内容
        memcpy(undo_stack[undo_top].data, lcd_mmap, sizeof(int) * SCREEN_WIDTH * SCREEN_HEIGHT);
        printf("保存成功 %d\n", undo_top);
    }
    redo_top = -1; // 每次保存清空恢复栈
}

// 撤销
void restore_state(int (*lcd_mmap)[SCREEN_WIDTH])
{
    if (undo_top > 0)
    {
        memcpy(lcd_mmap, undo_stack[undo_top - 1].data, sizeof(int) * SCREEN_WIDTH * SCREEN_HEIGHT);
        undo_top--;
        if (redo_top < REDO_STACK_SIZE - 1) // 每次撤销时将当前状态压入恢复栈
        {
            redo_top++;
            memcpy(redo_stack[redo_top].data, lcd_mmap, sizeof(int) * SCREEN_WIDTH * SCREEN_HEIGHT);
        }
        printf("撤销成功 %d\n", undo_top);
    }
    else
        printf("只剩最后一步！\n");
}

// 恢复上一个被撤销状态
void redo_state(int (*lcd_mmap)[SCREEN_WIDTH])
{
    if (redo_top >0)
    {
        memcpy(lcd_mmap, redo_stack[redo_top - 1].data, sizeof(int) * SCREEN_WIDTH * SCREEN_HEIGHT);
        redo_top--;
        if (undo_top < STACK_SIZE - 1)
        {
            undo_top++;
            memcpy(undo_stack[undo_top].data, lcd_mmap, sizeof(int) * SCREEN_WIDTH * SCREEN_HEIGHT);
        }
        printf("恢复成功 %d\n", redo_top);
    }
    else
    {
        printf("无法恢复！\n");
    }
}

// 显示初始操作界面
void LCD_clear(int num)
{
    int lcd_fd = open("/dev/fb0", O_RDWR);
    int(*lcd_mmap)[SCREEN_WIDTH] = (int(*)[SCREEN_WIDTH])mmap(NULL, SCREEN_WIDTH * SCREEN_HEIGHT * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);

    initialize_screen(lcd_mmap, num);

    close(lcd_fd);
}

// 绘制初始操作界面
void initialize_screen(int (*lcd_mmap)[SCREEN_WIDTH], int num)
{

    for (size_t row = 0; row < SCREEN_HEIGHT; row++)
    {
        for (size_t col = 0; col < SCREEN_WIDTH; col++)
        {
            // 将屏幕初始填充白色
            if (num == 0)
                lcd_mmap[row][col] = WHITE;
            else
                lcd_mmap[row][col] = color[color_index];

            // 右边边框
            if (col > SCREEN_WIDTH - RIGHT_MARGIN)
            {
                lcd_mmap[row][col] = GREY;
            }

            // 右上角填充一个40*40方块,用于显示清屏区域以及显示当前颜色
            if (row < 40 && col > 710)
            {
                lcd_mmap[row][col] = color[color_index];
            }

            // 绘制加号, 线条宽度区块
            if (row > 60 && row < 105 && col > 770 && col < 780)
            {
                lcd_mmap[row][col] = RED;
            }
            if (row > 78 && row < 88 && col > 755 && col < 795)
            {
                lcd_mmap[row][col] = RED;
            }
            // 绘制减号
            if (row > 78 && row < 88 && col > 710 && col < 750)
            {
                lcd_mmap[row][col] = RED;
            }

            // 在右边放置不同颜色方块, 用于切换颜色
            if (row > 120 && row <= 160 && col > 755 && col < 795)
            {
                lcd_mmap[row][col] = BLACK;
            }
            if (row > 170 && row <= 210 && col > 755 && col < 795)
            {
                lcd_mmap[row][col] = RED;
            }
            if (row > 220 && row <= 260 && col > 755 && col < 795)
            {
                lcd_mmap[row][col] = GREEN;
            }
            if (row > 120 && row <= 160 && col > 710 && col < 750)
            {
                lcd_mmap[row][col] = WHITE;
            }
            if (row > 170 && row <= 210 && col > 710 && col < 750)
            {
                lcd_mmap[row][col] = BLUE;
            }
            if (row > 220 && row <= 260 && col > 710 && col < 750)
            {
                lcd_mmap[row][col] = YELLOW;
            }
        }
    }
    show_bmp("./res/save.bmp", 716, 365);
    show_bmp("./res/withdraw.bmp", 700, 440);
    show_bmp("./res/restore.bmp", 750, 440);
    show_bmp("./res/exit.bmp", 0, 0);
    show_bmp("./res/background.bmp", 40, 0);
    show_bmp("./res/line.bmp", 80, 0);
    show_bmp("./res/round.bmp", 120, 0);
    show_bmp("./res/square.bmp", 160, 0);
}

// 处理触摸事件
void handle_touch_event(struct input_event touch_event, int (*lcd_mmap)[SCREEN_WIDTH], char *account)
{
    // 触摸按下事件 更新坐标并重置last_x和last_y
    if (touch_event.type == EV_KEY && touch_event.code == BTN_TOUCH && touch_event.value == 1)
    {
        // 重置上一个点的坐标
        last_x = x;
        last_y = y;
    }
    // 获取每次触摸坐标
    else if (touch_event.type == EV_ABS)
    {
        switch (touch_event.code)
        {
        case ABS_X:
            x = touch_event.value;
            break;
        case ABS_Y:
            y = touch_event.value;
            break;
        }
    }

    // 刷新功能区变更部分以及绘制
    if (touch_event.type == EV_SYN)
    {
        draw_interface(lcd_mmap);

        // 根据模式绘制不同图形
        if (draw_mode == 0)
        {
            // 只有在有上一个点的情况下才绘制直线
            if (last_x != -1 && last_y != -1)
            {
                if (last_x < 210 && last_y < 40) // 不在左上角功能区域
                {
                }
                else
                    draw_line(lcd_mmap, last_x, last_y, x, y); // 调用绘制直线的函数
            }
        }
        else if (draw_mode == 1)
        {
            draw_brush(lcd_mmap, x, y); // 绘制圆形
        }
        else if (draw_mode == 2)
        {
            draw_rectangle(lcd_mmap, x, y); // 绘制矩形
        }

        // 更新上一个点的坐标
        last_x = x;
        last_y = y;
    }

    // 根据触摸坐标选择对应功能(右边框功能区)
    if (touch_event.type == EV_KEY)
    {
        if (touch_event.code == BTN_TOUCH && touch_event.value == 1)
        {

            if (x > SCREEN_WIDTH - RIGHT_MARGIN)
            {
                if (y < 40)
                {
                    LCD_clear(0); // 清屏
                }
                else if (y > 440 && x < 750)
                {
                    restore_state(lcd_mmap); // 撤销
                    size_refresh(lcd_mmap);
                }
                else if (y > 440 && x > 750)
                {
                    redo_state(lcd_mmap); // 恢复
                    size_refresh(lcd_mmap);
                }
                else if (y > 365 && y < 440) // 保存当前画面
                {
                    char *num = rand_num();
                    if (save_screen_shot_as_bmp(lcd_mmap, num, account) == 0)
                    {
                        save_state(lcd_mmap);
                        show_bmp("./res/save_success.bmp", 360, 200);
                        sleep(1);
                        restore_state(lcd_mmap);
                    }
                }
            }

            if (y > 60 && y <= 105 && x > 755 && x < 790)
            {
                if (line < LINE_MAX)
                {
                    (line) += 5; // 线条加粗
                    size_refresh(lcd_mmap);
                }
            }
            if (y > 60 && y <= 105 && x > 710 && x < 750)
            {
                if (line > LINE_MIN)
                {
                    (line) -= 5; // 线条减小
                    size_refresh(lcd_mmap);
                }
            }
            if (y > 120 && y <= 160 && x > 755 && x < 795)
            {
                color[0] = BLACK;
                color_index = 0; // 选择黑色
            }
            if (y > 170 && y <= 210 && x > 755 && x < 795)
            {
                color[1] = RED;
                color_index = 1; // 选择红色
            }
            if (y > 220 && y <= 260 && x > 755 && x < 795)
            {
                color[2] = GREEN;
                color_index = 2; // 选择绿色
            }
            if (y > 120 && y <= 160 && x > 710 && x < 750)
            {
                color[5] = WHITE;
                color_index = 5; // 选择白色
            }
            if (y > 170 && y <= 210 && x > 710 && x < 750)
            {
                color[3] = BLUE;
                color_index = 3; // 选择蓝色
            }
            if (y > 220 && y <= 260 && x > 710 && x < 750)
            {
                color[4] = YELLOW;
                color_index = 4; // 选择黄色
            }
        }
    }
    // 按下离开后保存
    if (touch_event.type == EV_KEY && touch_event.code == BTN_TOUCH && touch_event.value == 0)
    {
        if (x < SCREEN_WIDTH - RIGHT_MARGIN) // 检查是否在右边功能区
        {
            if (x < 210 && y < 40) // 是否在左上角功能区域
            {
            }
            else
                save_state(lcd_mmap);
        }
    }
}

// 绘制画笔
void draw_brush(int (*lcd_mmap)[SCREEN_WIDTH], int x, int y)
{
    // 检查笔刷的 x 坐标是否在右边框内
    if (x > SCREEN_WIDTH - RIGHT_MARGIN)
    {
        return;
    }

    // 在x, y中心绘制半径为radius的圆
    for (int i = -line; i <= line; i++)
    {
        for (int j = -line; j <= line; j++)
        {
            // 计算圆的方程 (x - centerX)^2 + (y - centerY)^2 = radius^2
            if (i * i + j * j <= line * line)
            {
                int new_x = x + i;
                int new_y = y + j;
                // 确保在屏幕范围内
                if (new_x < 210 && new_y < 40)
                {
                    break;
                }

                if (new_x <= SCREEN_WIDTH - RIGHT_MARGIN && new_x >= 0 &&
                    new_y >= 0 && new_y < SCREEN_HEIGHT)
                {
                    lcd_mmap[new_y][new_x] = color[color_index];
                }
            }
        }
    }
}

// 绘制变更界面
void draw_interface(int (*lcd_mmap)[SCREEN_WIDTH])
{
    for (size_t row = 0; row < SCREEN_HEIGHT; row++)
    {
        for (size_t col = 0; col < SCREEN_WIDTH; col++)
        {
            // 右上角填充一个40*40方块,用于显示清屏区域以及显示当前颜色
            if (row < 40 && col > 710)
            {
                lcd_mmap[row][col] = color[color_index];
            }

            // 绘制圆形表示笔画大小
            if ((row - 320) * (row - 320) + (col - 750) * (col - 750) <= (line * line) / 2)
            {
                lcd_mmap[row][col] = color[color_index]; // 使用当前颜色填充圆形
            }
        }
    }
}

// 刷新画笔大小区域
void size_refresh(int (*lcd_mmap)[SCREEN_WIDTH])
{
    for (size_t row = 0; row < SCREEN_HEIGHT; row++)
    {
        for (size_t col = 0; col < SCREEN_WIDTH; col++)
        {
            if (row > 270 && row <= 365 && col > 700)
                lcd_mmap[row][col] = GREY;
        }
    }
}

// 绘制直线的函数
void draw_line(int (*lcd_mmap)[800], int x0, int y0, int x1, int y1)
{
    // 检查笔刷的 x 坐标是否在画布内
    if (x > SCREEN_WIDTH - RIGHT_MARGIN || (x < 210 && y < 40))
    {
        return;
    }
    int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
    int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
    int err = dx + dy, e2;

    while (1)
    {
        // 将当前点绘制到屏幕上
        set_pixel(lcd_mmap, x0, y0);

        if (x0 == x1 && y0 == y1)
            break;

        e2 = 2 * err;
        if (e2 >= dy)
        {
            err += dy;
            x0 += sx;
        }
        if (e2 <= dx)
        {
            err += dx;
            y0 += sy;
        }
    }
}

// 绘制矩形
void draw_rectangle(int (*lcd_mmap)[800], int x0, int y0)
{
    // 检查笔刷的 x 坐标是否在右边框内
    if (x > SCREEN_WIDTH - RIGHT_MARGIN || y > SCREEN_HEIGHT || (x < 210 && y < 40))
    {
        return;
    }
    // 绘制矩形(宽和高都为line)
    for (int i = 0; i < line; i++)
    {
        for (int j = 0; j < line; j++)
        {
            if ((y0 + i >= SCREEN_HEIGHT) || (x0 + j >= SCREEN_WIDTH - RIGHT_MARGIN) || (x0 + j < 210 && y0 + i < 40))
            {
                break;
            }

            lcd_mmap[y0 + i][x0 + j] = color[color_index];
        }
    }
}

// 扩展的 set_pixel 函数，用于绘制宽度大于1的线段
void set_pixel(int (*lcd_mmap)[800], int x, int y)
{
    // 计算线段的左右边界
    int left = x - line / 2;
    int right = x + line / 2;

    // 确保边界不会超出屏幕宽度
    if (left < 0)
        left = 0;
    if (right > SCREEN_WIDTH - RIGHT_MARGIN)
        right = SCREEN_WIDTH - RIGHT_MARGIN;

    // 绘制水平线段
    for (int col = left; col <= right; col++)
    {
        // 确保 y 值在屏幕高度范围内
        if (y >= 0 && y < SCREEN_HEIGHT)
        {
            lcd_mmap[y][col] = color[color_index];
        }
    }
}

// 辅助函数，用于填充矩形区域
void fill_rectangle(int (*lcd_mmap)[800])
{
    for (int row = 0; row < SCREEN_HEIGHT; row++)
    {
        for (int col = x; col < x + SCREEN_WIDTH; col++)
        {
            if (col >= 0 && col < SCREEN_WIDTH)
            { // 确保列坐标在屏幕宽度内
                lcd_mmap[row][col] = color[color_index];
            }
        }
    }
}

// 获取一个随机数用于保存文件名
char *rand_num()
{
    int numbers = 0;
    char *strNumbers = malloc(11 * sizeof(char)); // 10位数字 + 1个'\0'
    if (!strNumbers)
    {
        perror("Memory allocation failed");
        exit(EXIT_FAILURE);
    }
    // 初始化随机数生成器
    srand((unsigned int)time(NULL));

    numbers = rand();

    sprintf(strNumbers, "%d", numbers);

    return strNumbers;
}